package Controller;

import DiskManager.Disk;
import FileManager.FileManager;
import MemoryManager.Memory;
import MemoryManager.MemoryBlock;
import MemoryManager.Process;
import MemoryManager.Processinfo;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.control.TextArea;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import java.net.URL;
import java.util.*;

import static java.lang.Thread.sleep;

public class MainController implements Initializable {
    public Memory memory = null;

    public FileManager fm;

    public Disk disk;

    public MemoryBlock memoryBlock;

    private final Node rootIcon = new ImageView(new Image(getClass().getResourceAsStream("/UI/directory.png")));

    private static String originlocation = "root";

    private static String currentlocation;

    int test;
    Thread t;
    boolean OPEN = false;

    @FXML
    public StackPane stackpane;

    @FXML
    public TreeView<String> tree;

    @FXML
    public TableView<Processinfo> processManager;

    @FXML
    public TableView<Processinfo> resourceManager;

    @FXML
    public StackPane process;

    @FXML
    private TableColumn<Processinfo,Number> processID1;

    @FXML
    private TableColumn<Processinfo,Number> resourceA;

    @FXML
    private TableColumn<Processinfo,Number> resourceB;

    @FXML
    private TableColumn<Processinfo,Number> resourceC;

    @FXML
    private HBox memoryBox;

    @FXML
    private TextArea readyQueue;

    @FXML
    private TextArea blockedQueue;

    @FXML
    private TableColumn<Processinfo,Number> processID2;

    @FXML
    private TableColumn<Processinfo,String> status;

    @FXML
    private TableColumn<Processinfo,Number> pasttime;

    @FXML
    private TextArea cmdView;


    /**
     * 初始化文件管理窗口
     */
    public void fileManager() throws Exception{
        TreeItem<String> rootItem = new TreeItem<String>("root",rootIcon);
        rootItem.setExpanded(true);
        for (int i = 1; i < 10; i++) {
            TreeItem<String> item = new TreeItem<String>(i + ".exe");
            rootItem.getChildren().add(item);
        }
        TreeItem<String> item = new TreeItem<String>("big" + ".exe");
        rootItem.getChildren().add(item);
        tree = new TreeView<String>(rootItem);
        stackpane.getChildren().add(tree);
    }

    /**
     * 进程管理窗口数据绑定
     */
    public void processManager() throws Exception {

        //指定列绑定数据
        processID2.setCellValueFactory(new PropertyValueFactory<>("PID"));
        status.setCellValueFactory(new PropertyValueFactory<>("Status"));
        pasttime.setCellValueFactory(new PropertyValueFactory<>("Time"));

    }
    
    /*
     * 资源分配窗口数据绑定
     */
    public void resourceManager() throws Exception {

        //指定列绑定数据
        processID1.setCellValueFactory(new PropertyValueFactory<>("PID"));
        resourceA.setCellValueFactory(new PropertyValueFactory<>("OccupyA"));
        resourceB.setCellValueFactory(new PropertyValueFactory<>("OccupyB"));
        resourceC.setCellValueFactory(new PropertyValueFactory<>("OccupyC"));
    }

    /*
     * 获取进程占用资源状态
     */
    public void resourceInput() throws Exception {
        List<Process> processes = memory.getAllProcess();
        List<Processinfo> processInfos = new ArrayList<>(processes.size());
        for (Process process : processes) {
            Processinfo processInfo = new Processinfo(process, memory);
            processInfos.add(processInfo);
        }
        ObservableList<Processinfo> datas = FXCollections.observableList(processInfos);
        resourceManager();
        resourceManager.setItems(datas);
    }

    /*
     * 获取进程并且接收状态及占用cpu时间数据
     */
    
    public void processInput() throws Exception {

        //更新进程队列视图
        List<Process> processes = memory.getAllProcess();
        List<Processinfo> processInfos = new ArrayList<>(processes.size());
        for (Process process : processes) {
            Processinfo processInfo = new Processinfo(process, memory);
            processInfos.add(processInfo);
        }
        ObservableList<Processinfo> datas = FXCollections.observableList(processInfos);
        processManager();
        processManager.setItems(datas);
    }

    /**
     * 就绪队列初始化
     */
    public void initReadyQueue() throws Exception{
        List<Integer> readyPIDs = memory.getReadyQueue();
        String readyPID = readyPIDs.toString();
        readyQueue.setText(readyPID);
    }


    /**
     * 阻塞队列初始化
     */
    public void initBlockedQueue() throws Exception{
        List<Integer> blockedPIDs = memory.getBlockedQueue();
        String blockPID = blockedPIDs.toString();
        blockedQueue.setText(blockPID);
    }

    /**
     * 内存视图初始化
     */
    public void initMemoryView() throws Exception{
        LinkedList<MemoryBlock> memoryBlocks = memory.getBlocks();

        List<Rectangle> rl = new ArrayList<Rectangle>();
        for (int i = 0; i < memoryBlocks.size(); i++) {
            Rectangle r = new Rectangle();
            r.setWidth(memoryBlocks.get(i).getAllocated() * 6);
            r.setHeight(35);
            r.setStroke(Color.BLACK);
            if (memoryBlocks.get(i).isAvailable()) {
                r.setFill(Color.WHITE);
            } else {
                r.setFill(Color.RED);
            }
            rl.add(r);
        }

        memoryBox.getChildren().setAll(rl);
    }

    /**
     *
     * @param event 按键释放事件
     */
    public void executeCMD(KeyEvent event) throws Exception {
    
        //按下Enter键时触发
        if (event.getCode() == KeyCode.ENTER) {
            if (memory == null) memory = new Memory();
            OPEN = true;
            fileManager();
            //获取终端内文本内容
            String text = cmdView.getText();
            //以"\n"换行符为标记，分隔开每一行的文本内容
            String[] str = text.split("\\n");
            //获取最新一行的文本内容
            text = str[str.length - 1];
            //以">"最后一次出现的索引为标记，获取后续的文本内容即为指令内容
            int index = text.lastIndexOf(">");

            if(index >= 0 ){
                //获取指令部分
                text = text.substring(index + 1);
                //以"\\s"为分隔符，获取指令的前半部分，用于执行命令
                String[] cmd = text.split("\\s+");
                //">"后字符长度为标准，当小于一个字符时，就刷新下一行，否则执行对应命令
                if(text.length() <= 1){
                    cmdView.appendText(originlocation + ">");
                }else{
                    if(cmd[0].equals("cls")){
                        //清屏功能
                        cmdView.setText(originlocation + ">");
                    }else if(cmd[0].equals("cd")){
                        //进入下一层目录功能
                        currentlocation = originlocation + "/" + cmd[1];
                        cmdView.appendText(currentlocation + ">");
                    }else if(cmd[0].equals("run")){
                        //运行可执行文件
                        disk = new Disk();
                        fm = new FileManager(disk);
                        memory.addProcess(fm.readContentbyFileName(cmd[1]).trim());

                        cmdView.appendText("    ------->Process execute successfully" + "\n");
                        cmdView.appendText(originlocation + ">");
                    }else{
                        cmdView.appendText(originlocation + ">");
                    }
                }
            }
        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        // memory = new Memory();
        t = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        if (OPEN == true) {
                            // 刷新进程状态
                            processInput();
                            resourceInput();
                            initReadyQueue();
                            initBlockedQueue();
                            memory.SS();
                            Platform.runLater(new Runnable() {
                                @Override
                                public void run() {
                                    try {
                                        initMemoryView();
                                        
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                    }
                                }
                            });
                            memory.run();
                        }
                        // 刷新设备状态
                        sleep(1000);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        t.start();
    }


}
